﻿/*-------------------------------------------------------------------------
* 命名空间: XrayDirection.ViewModels/IndexViewModel
* 类       名: IndexViewModel
* 功      能:  TD
* 时      间:  2024/1/3 11:40:24
* 版      本:  V1.0
* 作      者:  Fioman
* 格      言:  Talk is cheap,show me the code ^_^
*-------------------------------------------------------------------------*/
using OpenCvSharp;
using Prism.Commands;
using Prism.Events;
using Prism.Ioc;
using Prism.Mvvm;
using SiliconSelect.Common;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Net;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Media;
using VisionProcess;
using XrayDirection.Common;
using XrayDirection.Common.EnumVal;
using XrayDirection.DAL.DataEntity;
using XrayDirection.DAL.LocalDataAccess;
using XrayDirection.Extensions;
using XrayDirection.HelperManager;
using XrayDirection.Models;
using XrayDirection.Services;
using XrayDirection.Views;

namespace XrayDirection.ViewModels
{
    public class IndexViewModel : BindableBase
    {
        public const int CamDelay = 10;
        private readonly IWindowService _windowService;
        private readonly IEventAggregator _eventAggregator;
        private readonly IContainerProvider _containerProvider;
        public IndexViewModel(IWindowService windowService, IEventAggregator eventAggregator, IContainerProvider containerProvider)
        {
            _windowService = windowService;
            _eventAggregator = eventAggregator;
            _containerProvider = containerProvider;
            // 先加载当前当前作业信息,作业工单,板编号,板最大编号等属性.
            InitWorkingInfo();
            RefreshWorkingInfo();
            // 初始化Order,如果Order无数据,先给Order里面添加一条默认的模拟数据.
            InitOrder();
            // 刷新显示正在作业的工单
            RefreshWorkingOrder();
            // 初始化设备状态
            InitDeviceState();
            // 更新界面要显示的图像,用来测试
            //TestXrayImageShow();
            ImageWidth = 640;
            ImageHeight = 480;
            // 初始化图像目录
            InitImageDir();
            ImageProcess.LoadTemplate();

            OpenGetImageCommand = new DelegateCommand(DoOpenGetImageTask, () => CanOpen)
                .ObservesProperty(() => CanOpen);

            CloseGetImageCommand = new DelegateCommand(DoCloseGetImageTask, () => CanClose)
                .ObservesProperty(() => CanClose);

            KeepImageXray01Command = new DelegateCommand(DoKeepImageXray01Task, () => CanClose)
                .ObservesProperty(() => CanClose);

            KeepImageXray02Command = new DelegateCommand(DoKeepImageXray02Task, () => CanClose)
                .ObservesProperty(() => CanClose);

            KeepImageTotalCommand = new DelegateCommand(DoKeepImageTotal, () => CanClose)
                .ObservesProperty(() => CanClose);

            ClearAlarmCommand = new DelegateCommand(DoClearAlarmTask);

            StartFromFirstCommand = new DelegateCommand(DoStartFromFirst);
            StartFromSecondCommand = new DelegateCommand(DoStartFromSecond);

            OpenImageXray01Command = new DelegateCommand(DoOpenImageXray01Task);
            OpenImageXray02Command = new DelegateCommand(DoOpenImageXray02Task);
            OpenImageTotalCommand = new DelegateCommand(DoOpenImageTotalTask);

            InputNextRecipeCommand = new DelegateCommand(DoInputNextRecipeCommandTask);
            ChangeNextRecipeCommand = new DelegateCommand(DoChangeNextRecipeCommandTask);
            EditRecipeCommand = new DelegateCommand(DoEditRecipeTask);
            _windowService = windowService;

            DeviceRunCommand = new DelegateCommand(DoDeviceRunTask);
            DeviceStopCommand = new DelegateCommand(DoDeviceStopTask);

            ModeChangeCommand = new DelegateCommand(DoModeChangeTask);

            _eventAggregator.GetEvent<RecipeChangeEvent>().Subscribe(OnRecipeChanged);

            InitModeList();
            StartAsyncTask();
            InitAlarmRecord();
        }

        private void DoStartFromSecond()
        {
            boardNumber = 2;
            SetFirstSecondMoveDis();
        }

        private void DoStartFromFirst()
        {
            boardNumber = 1;
            SetFirstSecondMoveDis();
        }

        private void OnRecipeChanged(string args)
        {
            // 重新写入PLC移动的值
            MoveDisIsWriteToPlc = false;
            SetFirstSecondMoveDis();
        }

        // 清空报警
        private void DoClearAlarmTask()
        {
            MainAlarmShowList.Clear();
        }

        private void InitAlarmRecord()
        {
            var result = AlarmRecordAccess.GetAlarms();
            if (result.State)
            {
                if (result.Data!.Count > 0)
                {
                    LogHelper.WriteLog("报警配置信息已经配置好,无须重新配置", LogType.Info);
                }
                else
                {
                    // 报警信息配置
                    List<Tuple<int, string, string>> alarmSettings = new List<Tuple<int, string, string>>()
                    {
                        new Tuple<int,string,string>(0,"居中机构_居中步进电机故障","物料拿出,重启复位设备"),
                        new Tuple<int,string,string>(1,"居中机构_居中步进正限位报警","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(2,"居中机构_居中步进负限位报警","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(3,"居中机构_居中步进指令故障","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(4,"旋转机构_X轴伺服故障","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(5,"旋转机构_X轴伺服正限位报警","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(6,"旋转机构_X轴伺服负限位报警","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(7,"旋转机构_X轴伺服指令故障","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(8,"旋转机构_Z轴伺服故障","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(9,"旋转机构_Z轴伺服正限位报警","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(10,"旋转机构_Z轴伺服负限位报警","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(11,"旋转机构_Z轴伺服指令故障","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(12,"旋转机构_R轴伺服故障","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(13,"旋转机构_R轴伺服正限位报警","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(14,"旋转机构_R轴伺服负限位报警","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(15,"旋转机构_R轴伺服指令故障","物料拿出,重启复位设备"),


                        new Tuple< int, string, string >(16,"X-Ray机构_左伺服故障","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(17,"X-Ray机构_左伺服正限位报警","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(18,"X-Ray机构_左伺服负限位报警","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(19,"X-Ray机构_左伺服指令故障","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(20,"X-Ray机构_右伺服故障","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(21,"X-Ray机构_右伺服正限位报警","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(22,"X-Ray机构_右伺服负限位报警","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(23,"X-Ray机构_右伺服指令故障","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(24,"翻转机构_Z轴伺服故障","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(25,"翻转机构_Z轴伺服正限位报警","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(26,"翻转机构_Z轴伺服负限位报警","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(27,"翻转机构_Z轴伺服指令故障","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(28,"翻转机构_R轴伺服故障","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(29,"翻转机构_R轴伺服正限位报警","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(30,"翻转机构_R轴伺服负限位报警","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(31,"翻转机构_R轴伺服指令故障","物料拿出,重启复位设备"),

                        new Tuple< int, string, string >(50,"与远程站心跳包报警","物料拿出,重启复位设备"),
                        new Tuple< int, string, string >(51,"与上位机心跳包报警","物料拿出,重启复位设备"),


                        new Tuple< int, string, string >(64,"1#旋转机构门禁报警","物料拿出,关闭1号门,重启复位设备"),
                        new Tuple< int, string, string >(65,"2#旋转机构门禁报警","物料拿出,关闭2号门,重启复位设备"),
                        new Tuple< int, string, string >(66,"3#旋转机构门禁报警","物料拿出,关闭3号门,重启复位设备"),
                        new Tuple< int, string, string >(67,"4#旋转机构门禁报警","物料拿出,关闭4号门,重启复位设备"),
                        new Tuple< int, string, string >(68,"5#旋转机构门禁报警","物料拿出,关闭5号门,重启复位设备"),
                        new Tuple< int, string, string >(69,"6#旋转机构门禁报警","物料拿出,关闭6号门,重启复位设备"),
                        new Tuple< int, string, string >(70,"7#旋转机构门禁报警","物料拿出,关闭7号门,重启复位设备"),
                        new Tuple< int, string, string >(71,"8#旋转机构门禁报警","物料拿出,关闭8号门,重启复位设备"),
                    };

                    foreach (var alarmInfo in alarmSettings)
                    {
                        AlarmEntity alarmAdded = new AlarmEntity();
                        alarmAdded.AlarmCode = $"P{alarmInfo.Item1}";
                        alarmAdded.Content = alarmInfo.Item2;
                        alarmAdded.SolutionHelp = alarmInfo.Item3;
                        alarmAdded.CreateTime = DateTimeHelper.GetTimeNowForSql();
                        AlarmRecordAccess.AddAlarmRecord(alarmAdded);
                    }

                }
            }
        }

        public DelegateCommand ClearAlarmCommand { get; private set; }

        public string lastAlarmCode = string.Empty;
        public string lastAlarmDes = string.Empty;
        public int lastAlarmLevel = -1;
        public int lastalarmStaus = -1;

        private async void RefreshAlarmShowList(List<int> alarmList)
        {
            MainAlarmShowList.Clear();
            string methodName = "DeviceAlarmReport";
            List<string> newAlarmList = new List<string>();
            // 这个时候表示PLC肯定是在线的,在线的时候去检测
            foreach (var alarmIndex in alarmList)
            {
                var result = AlarmRecordAccess.GetAlarmByCode($"P{alarmIndex}");
                if (result.State)
                {
                    if (result.Data != null)
                    {
                        var alarmNew = new AlarmEntity()
                        {
                            AlarmCode = result.Data.AlarmCode,
                            Content = result.Data.Content,
                            SolutionHelp = result.Data.SolutionHelp,
                            CreateTime = DateTimeHelper.GetTimeNowForSql()
                        };
                        MainAlarmShowList.Add(alarmNew);
                        string alarmCode = "AlarmInfo01";
                        string alarmDes = "居中机构电机出现了故障";
                        int alarmLevel = 3;
                        int alarmStaus = 1;
                        if (alarmNew.Content.Contains("居中机构电机"))
                        {
                            alarmCode = "AlarmInfo01";
                            alarmDes = "居中机构电机出现了故障";
                        }
                        else if (alarmNew.Content.Contains("旋转机构_X轴"))
                        {
                            alarmCode = "AlarmInfo02";
                            alarmDes = "旋转机构_X轴伺服故障";
                        }
                        else if (alarmNew.Content.Contains("X-Ray机构_左伺服故障"))
                        {
                            alarmCode = "AlarmInfo03";
                            alarmDes = "X-Ray机构_左伺服故障";
                        }
                        else if (alarmNew.Content.Contains("X-Ray机构_右伺服故障"))
                        {
                            alarmCode = "AlarmInfo04";
                            alarmDes = "X-Ray机构_右伺服故障";
                        }
                        else if (alarmNew.Content.Contains("翻转机构_Z轴伺服故障"))
                        {
                            alarmCode = "AlarmInfo05";
                            alarmDes = "翻转机构_Z轴伺服故障";
                        }
                        else if (alarmNew.Content.Contains("门禁报警"))
                        {
                            alarmCode = "AlarmInfo07";
                            alarmDes = "门禁报警";
                        }
                        lastAlarmCode = alarmCode;
                        lastAlarmDes = alarmDes;
                        lastAlarmLevel = alarmLevel;
                        lastalarmStaus = alarmStaus;
                        newAlarmList.Add(alarmCode + ":" + alarmDes); // 添加到newAlarmList中去
                    }
                    else
                    {
                        if (!lastAlarmCode.Equals(string.Empty))
                        {
                            var alarmResponse = await RequestHelper.RequestDeviceAlarmReport(methodName, lastAlarmCode, lastAlarmDes, lastAlarmLevel, lastalarmStaus);
                            RequestHelper.ParseNormalResponse(methodName, alarmResponse);
                            lastAlarmCode = string.Empty;
                            lastAlarmDes = string.Empty;
                            lastAlarmLevel = -1;
                            lastalarmStaus = -1;
                        }
                    }
                }
            }

            // 判断当前的newAlarmList和全局保存的alarmList是否是一样的,如果不一样,就说明有新的报警产生了
            if (newAlarmList.Count > GlobalValues.AlarmHappenList.Count)
            {
                // 获取在newAlarmList中,但是不再GlobalValues.AlarmHappenList中的报警
                var newAlarm = newAlarmList.Except(GlobalValues.AlarmHappenList).ToList();
                // 将这个报警信息进行上报
                foreach (var alarmInfo in newAlarm)
                {
                    string alarmInfoTemp = alarmInfo.Split(':')[0];
                    string alarmDescTemp = alarmInfo.Split(":")[1];
                    var alarmResponse = await RequestHelper.RequestDeviceAlarmReport(methodName, alarmInfoTemp, alarmDescTemp, 3, 1);
                    RequestHelper.ParseNormalResponse(methodName, alarmResponse);
                }
                GlobalValues.AlarmHappenList = new List<string>(newAlarmList);
            }
            else if (newAlarmList.Count < GlobalValues.AlarmHappenList.Count)
            {
                // 如果是小于,就证明就报警被回复了,这个时候要上报报警回复
                var alarmNew = GlobalValues.AlarmHappenList.Except(newAlarmList).ToList();
                // 将这个报警信息进行重置
                foreach (var alarmInfo in newAlarmList)
                {
                    string alarmInfoTemp = alarmInfo.Split(':')[0];
                    string alarmDescTemp = alarmInfo.Split(":")[1];
                    var alarmResponse = await RequestHelper.RequestDeviceAlarmReport(methodName, alarmInfoTemp, alarmDescTemp, 3, 0);
                    RequestHelper.ParseNormalResponse(methodName, alarmResponse);
                }
                GlobalValues.AlarmHappenList = new List<string>(newAlarmList);
            }
        }

        private ObservableCollection<AlarmEntity> mainAlarmShowList = new ObservableCollection<AlarmEntity>();

        public ObservableCollection<AlarmEntity> MainAlarmShowList
        {
            get { return mainAlarmShowList; }
            set
            {
                mainAlarmShowList = value;
                RaisePropertyChanged();
            }
        }


        private void InitModeList()
        {
            ModeList = new ObservableCollection<string>()
            {
                "直流",
                "旋转",
                "翻转",
                "旋转加翻转"
            };
            ModeSelectedIndex = 0;
        }

        private int modeSelectedIndex;

        public int ModeSelectedIndex
        {
            get { return modeSelectedIndex; }
            set
            {
                modeSelectedIndex = value;
                RaisePropertyChanged();
            }
        }


        private ObservableCollection<string> modeList;

        public ObservableCollection<string> ModeList
        {
            get { return modeList; }
            set
            {
                modeList = value;
                RaisePropertyChanged();
            }
        }




        // 是否是识别模式
        private bool isCalcMode = false;

        public bool IsCalcMode
        {
            get { return isCalcMode; }
            set
            {
                isCalcMode = value;
                RaisePropertyChanged();
            }
        }


        // 模式切换,先查看当前模式是什么模式
        private void DoModeChangeTask()
        {
            if (PlcClient.PlcState.IsOnline)
            {
                int changeVal = IsCalcMode ? 0 : 1;
                DataResult opRes = PlcClient.SetDeviceMode(changeVal);
                if (!opRes.State)
                {
                    LogHelper.WriteLog("Plc通信异常" + opRes.Message);
                    PlcClient.PlcState.IsOnline = false;
                    return;
                }
            }
            else
            {
                MessageProvider.ShowError("PLC未连接,请先连接PLC设备", "PLC未连接异常");
            }
        }

        public DelegateCommand ModeChangeCommand { get; private set; }

        /// <summary>
        /// 启动异步监听任务
        /// </summary>
        private async void StartAsyncTask()
        {
            // 启动异步任务进行监听工作
            Task plcMonitor = StartPlcMonitor();
            Task produceMonitor = StartProduceNew();
            Task xrayMonitor = StartXrayMonitor();
            Task eapMonitor = StartEapMonitor();
            Task webApiServer = StartWebApiServer();
            await Task.WhenAll(plcMonitor, produceMonitor, xrayMonitor, eapMonitor, webApiServer);
        }

        private CancellationTokenSource _webApiServerToken = new CancellationTokenSource();
        private async Task StartWebApiServer()
        {
            LogHelper.WriteLog("5. Web Api监听任务开启,开启Web Api监听任务!");
            string url = GlobalValues.WebApiUrl;
            HttpListener listener = new HttpListener();
            listener.Prefixes.Add(url);
            listener.Start();

            while (!_webApiServerToken.IsCancellationRequested)
            {
                HttpListenerContext conetxt = await listener.GetContextAsync();
                HttpListenerRequest request = conetxt.Request;
                HttpListenerResponse response = conetxt.Response;
                LogHelper.WriteLog($"收到webAPI的请求,请求的方法路径为: {request.Url!.AbsolutePath}");
                if (request.HttpMethod == "POST" && request.Url.AbsolutePath.Contains("EqpClearNotify"))
                {
                    using (StreamReader reader = new StreamReader(request.InputStream, request.ContentEncoding))
                    {
                        string requestBody = await reader.ReadToEndAsync();
                        LogHelper.WriteLog($"收到清线请求: {requestBody}");
                        RequestData requestData = JsonSerializer.Deserialize<RequestData>(requestBody);
                        if (requestData.FuncCode.Equals("Clear", StringComparison.OrdinalIgnoreCase))
                        {
                            await RequestHelper.RequestEqpClearFinish("EqpClearFinish");
                        }
                    }
                }
                await Task.Delay(500);
            }
        }

        private CancellationTokenSource _eapMonitorToken = new CancellationTokenSource();
        private async Task StartEapMonitor()
        {
            LogHelper.WriteLog("4. Eap监听任务,开启Eap监听任务!");
            var eapViewModel = _containerProvider.Resolve<EapViewModel>();
            while (!_eapMonitorToken.IsCancellationRequested)
            {
                await Task.Delay(5000);
                string methodName = "DeviceHeartbeat";
                var response = await RequestHelper.RequestDeviceHeartbeatAsync("DeviceHeartbeat");
                DataResult result = RequestHelper.ParseNormalResponse(methodName, response);
                if (result.State)
                {
                    if (!eapViewModel.EapIsOnline)
                    {
                        eapViewModel.EapIsOnline = true;
                        LogHelper.WriteLogEap("Eap在线,心跳请求成功");
                    }
                }
                else
                {
                    LogHelper.WriteLogEap("Eap不在线,心跳请求失败" + result.Message);
                    continue; // 如果不在线,就不继续往下面走了.
                }

                methodName = "DeviceStatusReport";
                // 更新设备状态
                if (PlcStopState)
                {
                    if ((int)GlobalValues.DeviceState != (int)StatusCode.待机 || !GlobalValues.FirstDeviceRequest)
                    {
                        await Task.Delay(5000);
                        GlobalValues.DeviceState = (int)StatusCode.待机;
                        response = await RequestHelper.RequestDeviceStatusReport(methodName, (int)StatusCode.待机, StatusCode.待机.ToString());
                        GlobalValues.FirstDeviceRequest = true;
                    }
                }
                else
                {
                    if ((int)GlobalValues.DeviceState != (int)StatusCode.运行 || !GlobalValues.FirstDeviceRequest)
                    {
                        await Task.Delay(5000);
                        GlobalValues.DeviceState = (int)StatusCode.运行;
                        response = await RequestHelper.RequestDeviceStatusReport(methodName, (int)StatusCode.运行, StatusCode.运行.ToString());
                        GlobalValues.FirstDeviceRequest = true;
                    }
                }

            }
            LogHelper.WriteLog("4. Eap监听取消,取消Eap监听任务!");
        }

        /// <summary>
        /// PLC连接已经断开次数
        /// </summary>
        public int PlcDisconnectedCount { get; set; }
        private PlcCommunication PlcClient = PlcCommunication.Instance;
        private CancellationTokenSource _plcMonitorToken = new CancellationTokenSource();
        private async Task StartPlcMonitor()
        {
            LogHelper.WriteLog("1. Plc监听线程开启,开启Plc监听任务!");
            while (!_plcMonitorToken.IsCancellationRequested)
            {
                await Task.Delay(1000);
                if (PlcDisconnectedCount >= 5)
                {
                    await Task.Delay(1000);
                    continue;
                }
                if (!PlcClient.PlcState.IsOnline)
                {
                    PlcClient.ConnectPlc();
                    if (!PlcClient.PlcState.IsOnline)
                    {
                        PlcDisconnectedCount++;
                        MainPlcState.IsOnline = false;
                        await Task.Delay(1000);
                        continue;
                    }
                    else
                    {
                        MainPlcState.IsOnline = true;
                    }
                }

                // 如果PLC连接成功以后,就读取PLC状态信息,先读取运行状态
                UpdatePlcState();

            }
            LogHelper.WriteLog("1. Plc监控线程取消,停止Plc监控任务!");
        }

        private async void UpdatePlcState()
        {
            DataResult<int> result = PlcClient.GetPlcRunningState();
            if (!result.State)
            {
                LogHelper.WriteLog("Plc通信异常" + result.Message);
                PlcClient.PlcState.IsOnline = false;
                return;
                //MessageProvider.ShowException(new Exception("PLC通信异常."), result.Message!);
                //return;
            }
            else
            {
                // 1. 手动中,就是停止状态
                if (result.Data == 1)
                {
                    PlcRunningState = false;
                    PlcStopState = true;
                    PlcResetState = false;
                }
                // 2. 自动中运行中
                else if (result.Data == 2)
                {
                    PlcStopState = false;
                    PlcRunningState = true;
                }
            }
            DataResult<float[]> xrayInfoResult = PlcClient.GetXrayParams();
            if (!xrayInfoResult.State)
            {
                LogHelper.WriteLog("Plc通信异常" + result.Message);
                PlcClient.PlcState.IsOnline = false;
                return;
            }
            else
            {
                // 
                float[] res = xrayInfoResult.Data!;
                Valtage01 = res[0].ToString("F3");
                Electricity01 = res[1].ToString("F3");
                Valtage02 = res[2].ToString("F3");
                Electricity02 = res[3].ToString("F3");
            }

            DataResult<int> modeRes = PlcClient.GetDeviceMode();
            if (!modeRes.State)
            {
                LogHelper.WriteLog("Plc通信异常" + result.Message);
                PlcClient.PlcState.IsOnline = false;
                return;
            }
            else
            {
                int modeVal = modeRes.Data;
                if (modeVal == 0)
                {
                    IsCalcMode = true;
                }
                else
                {
                    IsCalcMode = false;
                }
            }

            // 更新PLC报警信息,报警如果复位之后,
            var alarmRes = PlcClient.GetAlarmInfo();
            if (alarmRes.State)
            {
                List<int>? alarmDataList = alarmRes.Data;
                if (alarmDataList != null && alarmDataList.Count > 0)
                {
                    RefreshAlarmShowList(alarmDataList);
                }
                else
                {
                    if (GlobalValues.AlarmHappenList.Count > 0)
                    {
                        string methodName = "DeviceAlarmReport";
                        var alarmList = new List<string>(GlobalValues.AlarmHappenList);
                        foreach (var alarmInfo in alarmList)
                        {
                            string alarmInfoTemp = alarmInfo.Split(':')[0];
                            string alarmDescTemp = alarmInfo.Split(":")[1];
                            var alarmResponse = await RequestHelper.RequestDeviceAlarmReport(methodName, alarmInfoTemp, alarmDescTemp, 3, 0);
                            RequestHelper.ParseNormalResponse(methodName, alarmResponse);
                        }
                        GlobalValues.AlarmHappenList.Clear();
                    }
                }
            }
        }


        private CancellationTokenSource _xrayMonitorToken = new CancellationTokenSource();
        private async Task StartXrayMonitor()
        {
            LogHelper.WriteLog("2. Xray摄像头监听线程开启,开启摄像头监听任务!");
            DataResult<int>? checkResult;
            while (!_xrayMonitorToken.IsCancellationRequested)
            {
                await Task.Delay(100);
                // 这里主要用来判断Xray是否在线,以及实时刷新图像
                checkResult = ImageCapture.Instance.CheckIsOnlineAndFlush();
                if (!checkResult.State)
                {
                    if (checkResult.Data == 0)
                    {
                        bool res = MessageProvider.ShowOKCancel("两个摄像头都不在线,请检查USB线是否插入", "Xray摄像头出错");
                        if (!res)
                            // 如果取消,就忽略掉这个错误
                            _xrayMonitorToken.Cancel();
                    }
                    else if (checkResult.Data == 1)
                    {
                        bool res2 = MessageProvider.ShowOKCancel("只有一个摄像头在线,请检查两个USB线是否插入正确", "Xray摄像头出错");
                        if (!res2)
                            // 如果取消,就忽略掉这个错误
                            _xrayMonitorToken.Cancel();
                        XrayLeftState.IsOnline = true;
                    }
                }
                else
                {
                    XrayLeftState.IsOnline = true;
                    XrayRightState.IsOnline = true;
                }
            }
            LogHelper.WriteLog("2. Xray摄像头监听线程结束,关闭摄像头监听任务!");
        }



        private CancellationTokenSource _produceMonitorToken = new CancellationTokenSource();
        private async Task StartProduceNew()
        {
            LogHelper.WriteLog("3. 自动作业监听线程开启,开启自动作业任务.");
            bool findTargetFirstFinish = false;
            bool findTargetSecondFinish = false;
            while (!_produceMonitorToken.IsCancellationRequested)
            {
                await Task.Delay(50);
                if (PlcClient.PlcState.IsOnline)
                {
                    if (!MoveDisIsWriteToPlc)
                    {
                        SetFirstSecondMoveDis();
                    }
                    findTargetFirstFinish = false;
                    // 等待找靶标的拍照指令
                    while (!_produceMonitorToken.IsCancellationRequested && !findTargetFirstFinish)
                    {
                        await Task.Delay(5);
                        if (!IsCalcMode)
                        {
                            // 如果是直通模式就一直继续循环就行了
                            continue;
                        }
                        DataResult<int> findTargetRes = PlcClient.GetAllowFindTargetFirst();
                        if (!findTargetRes.State)
                        {
                            LogHelper.WriteLog($"Id_{WorkingInfos[0].BorderIndex} 获取第一次找靶标信号失败: {findTargetRes.Message}!");
                            LogHelper.WriteLog("Plc通信异常" + findTargetRes.Message);
                            PlcClient.PlcState.IsOnline = false;
                            return;
                        }
                        if (findTargetRes.Data == 1)
                        {
                            LogHelper.WriteLog($"Id_{WorkingInfos[0].BorderIndex} 第一次找靶标收到拍照信号.");
                            // Todo 获取第一次照片并且处理结果.
                            await Task.Delay(CamDelay);
                            var flushRes = ImageCapture.Instance.CheckIsOnlineAndFlush();
                            if (!flushRes.State)
                            {
                                MessageProvider.ShowError("相机拍照失败,请确定相机USB是否插入成功!", "相机取图失败提示框");
                                return;
                            }
                            var imageRes01 = ImageCapture.Instance.GetImage01();
                            if (!imageRes01.State)
                            {
                                MessageProvider.ShowError("相机取图失败,请确定摄像头USB是否插入成功!", "相机取图失败提示框");
                                return;
                            }
                            var imageRes02 = ImageCapture.Instance.GetImage02();
                            if (!imageRes02.State)
                            {
                                MessageProvider.ShowError("相机取图失败,请确定摄像头USB是否插入成功!", "相机取图失败提示框");
                                return;
                            }

                            OperateResult<Tuple<double, Mat>> targetRes = ImageProcess.FindTargetInfo(imageRes01.Data!, 1);
                            if (targetRes.State)
                            {
                                // 设置动作方向
                                SetDirectionFromRes(1, 1);
                                UpLoadDataCraft(true);
                                // 如果是第一次就找到了,就结束找靶标了.
                                var setRes = PlcClient.SetFindTargetFirstFinish();
                                if (!setRes.State)
                                {
                                    LogHelper.WriteLog($"SetFindTargetFirstFinish()出错了: {setRes.Message}");
                                    return;
                                }
                                LogHelper.WriteLog($"Id_{WorkingInfos[0].BorderIndex} 告诉PLC第一次找靶标结束,找到目标,结束找靶标流程!");
                                UpdateOneBoardFinish(true);
                                // 显示图片
                                ImageResXray01 = targetRes.Data!.Item2;
                                ImageResXray02 = imageRes02.Data;
                                // 保存图片
                                ImageCapture.SaveTargetImageOk(WorkingInfos[0].BorderIndex, imageRes01.Data!, "first_01");
                                ImageCapture.SaveTargetImageOk(WorkingInfos[0].BorderIndex, imageRes02.Data!, "first_02");
                                ImageCapture.SaveTargetImageRes(workingInfos[0].BorderIndex, targetRes.Data!.Item2, "first_01");
                                continue;
                            }

                            targetRes = ImageProcess.FindTargetInfo(imageRes02.Data!, 2);
                            if (targetRes.State)
                            {
                                // 设置动作方向
                                SetDirectionFromRes(2, 1);
                                UpLoadDataCraft(true);
                                // 如果是第一次就找到了,就结束找靶标了.
                                var setRes = PlcClient.SetFindTargetFirstFinish();
                                if (!setRes.State)
                                {
                                    LogHelper.WriteLog($"SetFindTargetFirstFinish()出错了: {setRes.Message}");
                                    return;
                                }
                                LogHelper.WriteLog($"Id_{WorkingInfos[0].BorderIndex} 告诉PLC第一次找靶标结束,找到目标,结束找靶标流程!");
                                UpdateOneBoardFinish(true);
                                // 显示图片
                                ImageResXray02 = targetRes.Data!.Item2;
                                ImageResXray01 = imageRes01.Data;

                                // 保存图片
                                ImageCapture.SaveTargetImageOk(WorkingInfos[0].BorderIndex, imageRes01.Data!, "first_01");
                                ImageCapture.SaveTargetImageOk(WorkingInfos[0].BorderIndex, imageRes02.Data!, "first_02");
                                ImageCapture.SaveTargetImageRes(workingInfos[0].BorderIndex, targetRes.Data!.Item2, "first_02");
                                continue;
                            }

                            var setRes02 = PlcClient.SetFindTargetFirstFinish();
                            if (!setRes02.State)
                            {
                                LogHelper.WriteLog($"SetFindTargetFirstFinish()出错了: {setRes02.Message}");
                                return;
                            }
                            LogHelper.WriteLog($"Id_{WorkingInfos[0].BorderIndex} 告诉PLC第一次找靶标结束,未找到目标,进行第二次找靶标流程!");
                            ImageResXray01 = imageRes01.Data;
                            ImageResXray02 = imageRes02.Data;
                            //ImageCapture.SaveTargetImageOk(WorkingInfos[0].BorderIndex, imageRes01.Data!, "first_01");
                            //ImageCapture.SaveTargetImageOk(WorkingInfos[0].BorderIndex, imageRes02.Data!, "first_02");
                            // 失败的时候要保存的失败的图像
                            Mat failImage01 = imageRes01.Data!.Clone();
                            Mat failImage02 = imageRes02.Data!.Clone();
                            findTargetFirstFinish = true;
                            findTargetSecondFinish = false;
                            while (!_produceMonitorToken.IsCancellationRequested && !findTargetSecondFinish)
                            {
                                await Task.Delay(5);
                                if (!IsCalcMode)
                                {
                                    // 如果是直通模式就一直继续循环就行了
                                    continue;
                                }
                                findTargetRes = PlcClient.GetAllowFindTargetSecond();
                                if (!findTargetRes.State)
                                {
                                    return;
                                }

                                if (findTargetRes.Data == 1)
                                {
                                    LogHelper.WriteLog($"Id_{WorkingInfos[0].BorderIndex} 第二次找靶标收到拍照信号!");
                                    flushRes = ImageCapture.Instance.CheckIsOnlineAndFlush();
                                    if (!flushRes.State)
                                    {
                                        MessageProvider.ShowError("相机拍照失败,请确定相机USB是否插入成功!", "相机取图失败提示框");
                                        return;
                                    }
                                    imageRes01 = ImageCapture.Instance.GetImage01();
                                    if (!imageRes01.State)
                                    {
                                        MessageProvider.ShowError("相机取图失败,请确定摄像头USB是否插入成功!", "相机取图失败提示框");
                                        return;
                                    }
                                    imageRes02 = ImageCapture.Instance.GetImage02();
                                    if (!imageRes02.State)
                                    {
                                        MessageProvider.ShowError("相机取图失败,请确定摄像头USB是否插入成功!", "相机取图失败提示框");
                                        return;
                                    }
                                    targetRes = ImageProcess.FindTargetInfo(imageRes01.Data!, 1);
                                    if (targetRes.State)
                                    {
                                        // 设置动作方向
                                        SetDirectionFromRes(1, 2);
                                        UpLoadDataCraft(true); // 更新数据

                                        // 如果是第一次就找到了,就结束找靶标了.
                                        var setRes = PlcClient.SetFindTargetSecondFinish();
                                        if (!setRes.State)
                                        {
                                            LogHelper.WriteLog($"SetFindTargetFirstFinish()出错了: {setRes.Message}");
                                            return;
                                        }
                                        LogHelper.WriteLog($"Id_{WorkingInfos[0].BorderIndex} 告诉PLC第二次找靶标结束,找到目标,结束找靶标流程!");
                                        UpdateOneBoardFinish(true);
                                        // 显示图片
                                        ImageResXray01 = targetRes.Data!.Item2;
                                        ImageResXray02 = imageRes02.Data;
                                        // 保存图片
                                        ImageCapture.SaveTargetImageOk(WorkingInfos[0].BorderIndex, imageRes01.Data!, "second_01");
                                        ImageCapture.SaveTargetImageOk(WorkingInfos[0].BorderIndex, imageRes02.Data!, "second_02");
                                        ImageCapture.SaveTargetImageRes(workingInfos[0].BorderIndex, targetRes.Data!.Item2, "second_01");
                                        findTargetSecondFinish = true;
                                        continue;
                                    }


                                    targetRes = ImageProcess.FindTargetInfo(imageRes02.Data!, 2);
                                    if (targetRes.State)
                                    {
                                        // 设置动作方向
                                        SetDirectionFromRes(2, 2);
                                        UpLoadDataCraft(true);
                                        var setRes = PlcClient.SetFindTargetSecondFinish();
                                        if (!setRes.State)
                                        {
                                            LogHelper.WriteLog($"SetFindTargetFirstFinish()出错了: {setRes.Message}");
                                            return;
                                        }
                                        LogHelper.WriteLog($"Id_{WorkingInfos[0].BorderIndex} 告诉PLC第二次找靶标结束,找到目标,结束找靶标流程!");
                                        UpdateOneBoardFinish(true);
                                        // 显示图片
                                        ImageResXray02 = targetRes.Data!.Item2;
                                        ImageResXray01 = imageRes01.Data;
                                        // 保存图片
                                        ImageCapture.SaveTargetImageOk(WorkingInfos[0].BorderIndex, imageRes01.Data!, "second_01");
                                        ImageCapture.SaveTargetImageOk(WorkingInfos[0].BorderIndex, imageRes02.Data!, "second_02");
                                        ImageCapture.SaveTargetImageRes(workingInfos[0].BorderIndex, targetRes.Data!.Item2, "second_02");
                                        findTargetSecondFinish = true;
                                        continue;
                                    }


                                    // 如果都没有找到靶标,就认为是找靶标失败.

                                    ImageResXray01 = imageRes01.Data;
                                    ImageResXray02 = imageRes02.Data;

                                    ImageCapture.SaveTargetImageFail(WorkingInfos[0].BorderIndex, imageRes01.Data!, "second_01");
                                    ImageCapture.SaveTargetImageFail(WorkingInfos[0].BorderIndex, imageRes02.Data!, "second_02");
                                    ImageCapture.SaveTargetImageFail(WorkingInfos[0].BorderIndex, failImage01, "first_01");
                                    ImageCapture.SaveTargetImageFail(WorkingInfos[0].BorderIndex, failImage02, "first_02");

                                    // 设置结果为直流,如果都没有两次都没有找到结果
                                    // 设置靶标结果,目前是随机的写入1,2,3,4
                                    setRes02 = PlcClient.SetCalcResult(CalcResType.Direct);
                                    UpLoadDataCraft(false);
                                    if (!setRes02.State)
                                    {
                                        LogHelper.WriteLog($"SetCalcResult()出错了: {setRes02.Message}");
                                        return;
                                    }
                                    setRes02 = PlcClient.SetFindTargetSecondFinish();
                                    if (!setRes02.State)
                                    {
                                        LogHelper.WriteLog($"SetFindTargetFirstFinish()出错了: {setRes02.Message}");
                                        return;
                                    }
                                    LogHelper.WriteLog($"Id_{WorkingInfos[0].BorderIndex} 两次都没有找到目标: 设置动作为直流, 告诉Plc第二次找靶标结束: {setRes02.Message}!");
                                    UpdateOneBoardFinish(false);
                                    findTargetSecondFinish = true;
                                }
                            }
                        }
                    }
                }
                else
                {
                    continue;
                }
            }
            LogHelper.WriteLog("3. 自动作业监听线程取消,停止自动作业任务.");
        }

        // 上报工艺质量
        private async void UpLoadDataCraft(bool isOK)
        {
            // 更新设备工艺参数
            string methodName = "DeviceCraftReport";
            var response = await RequestHelper.RequestDeviceCraftReportExt(methodName);
            RequestHelper.ParseNormalResponse(methodName, response);
            //methodName = "PanelCheckReport";
            //response = await RequestHelper.RequestPanelCheckReport(methodName, isOK);
            //RequestHelper.ParseNormalResponse(methodName, response);
        }

        public DelegateCommand StartFromFirstCommand { get; private set; }
        public DelegateCommand StartFromSecondCommand { get; private set; }

        // 更新工单信息,是良品还是非良品,每次作业完成一次,要更新一下移动距离.
        private void UpdateOneBoardFinish(bool isOK)
        {
            // 更改第一块还是第二块
            if (boardNumber == 1)
            {
                boardNumber = 2;
            }
            else
            {
                boardNumber = 1;
            }
            SetFirstSecondMoveDis();
            if (WorkingInfos[0].BorderIndex >= WorkingInfos[0].BorderIndexMax)
            {
                WorkingInfos[0].BorderIndex = 1;
            }
            else
            {
                WorkingInfos[0].BorderIndex += 1;
            }
            WorkingInfoAccess.UpdateWorkingInfo(WorkingInfos[0]);

            // 更新作业工单信息
            if (isOK)
            {
                WorkingOrders[0].OkCount += 1;
            }
            else
            {
                WorkingOrders[0].FailCount += 1;
            }
            OrderAccess.UpdateOrder(WorkingOrders[0]);
            RefreshWorkingInfo();
        }

        public int FirstMove = 200;
        public int SecondMove = 200;

        // 第一次移动是否是寻找方向靶标.
        /*
         * 如果第一次移动D+F+Offset,这个时候方向是反的.
         * 如果第一次移动了DFO,那么调整的方案是.
         * 如果第一次Xray01找到了,那么就翻转就行了
         * 如果第一次Xray02找到了,那么就旋转+翻转
         * 如果第二次Xray01找到了,那么就直接走就行了
         * 如果第二次Xray2找到了,那么就旋转就行了.
         * 
         * 如果第一次不是移动的D+F+Offset是另外一个方向
         * 如果第一次Xray01找到了,那么就直接走就行了
         * 如果第一次Xray02找到了,那么就旋转
         * 如果第二次Xray01找到了,那么就直接翻转
         * 如果第二次Xray02找到了,那么就直接旋转+翻转
         */

        public CalcResType DirectionResult { get; set; }

        public void SetDirectionFromRes(int xrayIndex, int findTimes)
        {
            if (xrayIndex == 1)
            {
                if (FirstMoveDFO)
                {
                    if (findTimes == 1)
                    {
                        DirectionResult = CalcResType.RotateAndFlip;
                    }
                    else
                    {
                        DirectionResult = CalcResType.Rotate;
                    }
                }
                else
                {
                    if (findTimes == 1)
                    {
                        DirectionResult = CalcResType.Rotate;
                    }
                    else
                    {
                        DirectionResult = CalcResType.RotateAndFlip;
                    }
                }
            }
            else
            {
                if (FirstMoveDFO)
                {
                    if (findTimes == 1)
                    {
                        DirectionResult = CalcResType.Direct;
                    }
                    else
                    {
                        DirectionResult = CalcResType.Flip;
                    }
                }
                else
                {
                    if (findTimes == 1)
                    {
                        DirectionResult = CalcResType.Flip;
                    }
                    else
                    {
                        DirectionResult = CalcResType.Direct;
                    }
                }
            }

            // 测试翻板动作,所有的板子的动作都改成翻板
            //DirectionResult = CalcResType.Flip;
            var setRes = PlcClient.SetCalcResult(DirectionResult);
            if (!setRes.State)
            {
                LogHelper.WriteLog($"SetCalcResult()出错了: {setRes.Message}");
                return;
            }
            LogHelper.WriteLog($"Id_{WorkingInfos[0].BorderIndex} 移动方式DFO:{FirstMoveDFO},第{findTimes}次,Xray0{xrayIndex} 找到目标, 计算结果为: {DirectionResult},对应的数字为{(int)DirectionResult}.");
        }

        public bool FirstMoveDFO = true;
        public bool MoveDisIsWriteToPlc = false;
        public int boardNumber = 1; // 第一块还是第二块

        private void SetFirstSecondMoveDis()
        {
            OrderEntity orderUsed = WorkingOrders[0];
            int moveOffset;
            if (boardNumber == 1)
            {
                moveOffset = Convert.ToInt32(orderUsed.MoveOffset);
            }
            else
            {
                moveOffset = Convert.ToInt32(orderUsed.MoveOffset02);
            }
            double move1 = orderUsed.FrontEdgeDisD * 25.4 + orderUsed.DirectHoleDisF * 25.4 + moveOffset;
            double move2 = orderUsed.LongLengthX * 25.4 - orderUsed.FrontEdgeDisD * 25.4 - orderUsed.DirectHoleDisF * 25.4 + moveOffset;
            if (move1 < move2)
            {
                FirstMove = Convert.ToInt32(move1);
                SecondMove = Convert.ToInt32(move2 - move1);
                FirstMoveDFO = true;
            }
            else if (move2 < move1)
            {
                FirstMoveDFO = false;
                FirstMove = Convert.ToInt32(move2);
                SecondMove = Convert.ToInt32(move1 - move2);
            }
            else
            {
                FirstMove = Convert.ToInt32(move1 - 50);
                SecondMove = Convert.ToInt32(move2 + 50);
            }

            DataResult opRes = PlcClient.SetFirstMove(FirstMove);
            if (!opRes.State)
            {
                LogHelper.WriteLog("Plc通信异常" + opRes.Message);
                PlcClient.PlcState.IsOnline = false;
            }

            // 靶距Y
            int disY = Convert.ToInt32(orderUsed.ShortLengthY * 25.4);
            opRes = PlcClient.SetTargetDisY(disY);
            if (!opRes.State)
            {
                LogHelper.WriteLog("Plc通信异常" + opRes.Message);
                PlcClient.PlcState.IsOnline = false;
            }

            opRes = PlcClient.SetSecondMove(SecondMove);
            if (!opRes.State)
            {
                LogHelper.WriteLog("Plc通信异常" + opRes.Message);
                PlcClient.PlcState.IsOnline = false;
            }
            else
            {
                LogHelper.WriteLog($"第{boardNumber}块写入参数,firstMove = {FirstMove},secondMove = {SecondMove}, Y = {disY},Offset = {moveOffset},FristMoveDFO = {FirstMoveDFO}");
                MoveDisIsWriteToPlc = true;
            }
        }

        private void DoDeviceStopTask()
        {
            DataResult stopRes = PlcCommunication.Instance.StopPlc();
            if (!stopRes.State)
            {
                MessageProvider.ShowError(stopRes.Message!, "Plc停止失败");
            }
            else
            {
                LogHelper.WriteLog("界面上点击了停止按钮,停止Plc成功");
            }
        }

        private void DoDeviceRunTask()
        {
            DataResult startRes = PlcCommunication.Instance.StartPlc();
            if (!startRes.State)
            {
                MessageProvider.ShowError(startRes.Message!, "Plc运行失败");
            }
            {
                LogHelper.WriteLog("界面上点击了运行按钮,运行Plc成功");
            }
        }

        public DelegateCommand DeviceRunCommand { get; private set; }
        public DelegateCommand DeviceStopCommand { get; private set; }

        // 点击了切换下一单的指令,弹窗切换下一单的界面
        private void DoChangeNextRecipeCommandTask()
        {
            LogHelper.WriteLog("界面上点击了工单切换命令");
            _windowService.ShowWindow(nameof(ChangeNextRecipeView));
        }

        /// <summary>
        /// 执行输入下一单的命令的任务
        /// </summary>
        private void DoInputNextRecipeCommandTask()
        {
            LogHelper.WriteLog("界面上点击了工单录入命令");
            _windowService.ShowWindow(nameof(InputNextRecipeView));
        }

        private void DoEditRecipeTask()
        {
            LogHelper.WriteLog("界面上点击了编辑工单命令");
            _windowService.ShowWindow(nameof(EditRecipeView));
        }

        /// <summary>
        /// 输入下一单
        /// </summary>
        public DelegateCommand InputNextRecipeCommand { get; private set; }
        /// <summary>
        /// 切换下一单
        /// </summary>
        public DelegateCommand ChangeNextRecipeCommand { get; private set; }

        // 编辑当前工单
        public DelegateCommand EditRecipeCommand { get; private set; }


        private void DoOpenImageTotalTask()
        {
            FileDirHelper.OpenDirAndSelected(ConstantManager.ToolDirXray01, ToolImageFilename01);
            FileDirHelper.OpenDirAndSelected(ConstantManager.ToolDirXray02, ToolImageFilename02);
        }

        private void DoOpenImageXray02Task()
        {
            FileDirHelper.OpenDirAndSelected(ConstantManager.ToolDirXray02, ToolImageFilename02);
        }

        private void DoOpenImageXray01Task()
        {
            FileDirHelper.OpenDirAndSelected(ConstantManager.ToolDirXray01, ToolImageFilename01);
        }

        private void DoKeepImageTotal()
        {
            ToolImageFilename01 = $"{ToolImageIndex}--{DateTimeHelper.GetTimeNowForKeepImage()}--01.bmp";
            ToolImageFilename02 = $"{ToolImageIndex}--{DateTimeHelper.GetTimeNowForKeepImage()}--02.bmp";
            if (ImageShowTool01 != null)
            {
                Cv2.ImWrite(Path.Combine(ConstantManager.ToolDirXray01, ToolImageFilename01), ImageShowTool01);
            }
            else
            {
                MessageProvider.ShowError("Xray01图像为空,请检查Xray摄像头的USB插入是否正确,并且是否打开了实时取图", "取图错误");
                return;
            }
            if (ImageShowTool02 != null)
            {
                Cv2.ImWrite(Path.Combine(ConstantManager.ToolDirXray02, ToolImageFilename02), ImageShowTool02);
                MessageProvider.ShowInfo("保存成功!", "取图OK");
                ToolImageIndex++;
            }
            else
            {
                MessageProvider.ShowError("Xray02图像为空,请检查Xray摄像头的USB插入是否正确并且是否打开了实时取图", "取图错误");
            }
        }

        private void DoKeepImageXray02Task()
        {
            ToolImageFilename02 = $"{ToolImageIndex}--{DateTimeHelper.GetTimeNowForKeepImage}--02.bmp";
            if (ImageShowTool02 != null)
            {
                Cv2.ImWrite(Path.Combine(ConstantManager.ToolDirXray02, ToolImageFilename02), ImageShowTool02);
                MessageProvider.ShowInfo("保存成功!", "取图OK");
                ToolImageIndex++;
            }
            else
            {
                MessageProvider.ShowError("Xray02图像为空,请检查Xray摄像头的USB插入是否正确并且是否打开了实时取图", "取图错误");
            }

        }

        private void DoKeepImageXray01Task()
        {
            ToolImageFilename01 = $"{ToolImageIndex}--{DateTimeHelper.GetTimeNowForKeepImage}--01.bmp";
            if (ImageShowTool01 != null)
            {
                Cv2.ImWrite(Path.Combine(ConstantManager.ToolDirXray01, ToolImageFilename01), ImageShowTool01);
                MessageProvider.ShowInfo("保存成功!", "取图OK");
                ToolImageIndex++;
            }
            else
            {
                MessageProvider.ShowError("Xray01图像为空,请检查Xray摄像头的USB插入是否正确,并且是否打开了实时取图", "取图错误");
            }
        }


        // 初始化图像目录,以后看看还有没有其他目录
        // 1. 初始化工具的图像目录,并且找到图像目录中的图标的最大值作为工具图像的索引.
        public void InitImageDir()
        {
            // 初始化生产作业保存图像的目录
            ConstantManager.FindEdgeDir = Path.Combine(Path.Combine(ConstantManager.FindEdgeRoot, DateTimeHelper.GetTimeNowForDir()),
                WorkingInfos[0].WorkingRecipeName!);
            ConstantManager.FindTargetDir = Path.Combine(Path.Combine(ConstantManager.FindTargetRoot, DateTimeHelper.GetTimeNowForDir()),
                WorkingInfos[0].WorkingRecipeName!);
            FileDirHelper.CreateDir(ConstantManager.FindEdgeDir);
            FileDirHelper.CreateDir(ConstantManager.FindTargetDir);

            ConstantManager.FindEdgeDirOk = Path.Combine(ConstantManager.FindEdgeDir, "OK");
            ConstantManager.FindEdgeDirFail = Path.Combine(ConstantManager.FindEdgeDir, "Fail");
            ConstantManager.FindEdgeDirRes = Path.Combine(ConstantManager.FindEdgeDir, "Res");
            FileDirHelper.CreateDir(ConstantManager.FindEdgeDirOk);
            FileDirHelper.CreateDir(ConstantManager.FindEdgeDirFail);
            FileDirHelper.CreateDir(ConstantManager.FindEdgeDirRes);


            ConstantManager.FindTargetDirOk = Path.Combine(ConstantManager.FindTargetDir, "OK");
            ConstantManager.FindTargetDirFail = Path.Combine(ConstantManager.FindTargetDir, "Fail");
            ConstantManager.FindTargetDirRes = Path.Combine(ConstantManager.FindTargetDir, "Res");
            FileDirHelper.CreateDir(Path.Combine(ConstantManager.FindTargetDir, "OK"));
            FileDirHelper.CreateDir(Path.Combine(ConstantManager.FindTargetDir, "Fail"));
            FileDirHelper.CreateDir(Path.Combine(ConstantManager.FindTargetDir, "Res"));

            // 模板目录创建
            FileDirHelper.CreateDir(ConstantManager.TemplateOriginalDir);
            FileDirHelper.CreateDir(ConstantManager.TemplateDir01);
            FileDirHelper.CreateDir(ConstantManager.TemplateDir02);


            FileDirHelper.CreateDir(ConstantManager.ToolDirXray01);
            FileDirHelper.CreateDir(ConstantManager.ToolDirXray02);
            var files01 = FileDirHelper.GetTotalFiles(ConstantManager.ToolDirXray01);
            var files02 = FileDirHelper.GetTotalFiles(ConstantManager.ToolDirXray02);
            if (files01.Length == 0)
            {
                ToolImageIndex = 0;
            }
            else
            {
                ToolImageIndex = files01.Select(filePath =>
                {
                    var parts = filePath.Split(new[] { "--" }, StringSplitOptions.None);
                    //LogHelper.WriteLog($"parts[0] = {parts[0]}");
                    if (parts.Length > 0 && int.TryParse(parts[0], out int number))
                    {
                        return number;
                    }
                    return 0;
                }).Max();
            }

            if (files02.Length > 0)
            {
                int index02 = files02.Select(filePath =>
                {
                    var parts = filePath.Split(new[] { "--" }, StringSplitOptions.None);
                    if (parts.Length > 0 && int.TryParse(parts[0], out int number))
                    {
                        return number;
                    }
                    return 0;
                }).Max();
                if (index02 > toolImageIndex)
                {
                    toolImageIndex = index02;
                }
            }
        }

        // Xray01图像的文件名
        private string? toolImageFilename01;

        public string? ToolImageFilename01
        {
            get { return toolImageFilename01; }
            set
            {
                toolImageFilename01 = value;
                RaisePropertyChanged();
            }
        }

        // Xray02图像的文件名
        private string? toolImageFilename02;

        public string? ToolImageFilename02
        {
            get { return toolImageFilename02; }
            set
            {
                toolImageFilename02 = value;
                RaisePropertyChanged();
            }
        }


        private bool canOpen = true;

        public bool CanOpen
        {
            get { return canOpen; }
            set
            {
                canOpen = value;
                CanClose = !CanOpen;
                RaisePropertyChanged();
            }
        }

        private bool canClose;

        public bool CanClose
        {
            get { return canClose; }
            set
            {
                canClose = value;
                RaisePropertyChanged();
            }
        }


        /// <summary>
        /// 图像编号的索引,每次运行的时候,按照文件的个数,去自动的增加编号
        /// </summary>
        private int toolImageIndex;

        public int ToolImageIndex
        {
            get { return toolImageIndex; }
            set
            {
                toolImageIndex = value;
                RaisePropertyChanged();
            }
        }

        private void DoCloseGetImageTask()
        {
            CanOpen = true;
            GetImageTaskToken?.Cancel();
        }

        CancellationTokenSource? GetImageTaskToken = null;

        // 执行刷新图像的任务,这里你目前的思路是什么呢,就是不停的往两个变量里面刷新图像,然后创建一个TaskToken,任务是可以取消的.
        private void DoOpenGetImageTask()
        {
            // 为什么这里要在这里创建TokenSource呢?
            // 因为如果建在外面,TokenSource取消之后就不能再次复用,就一直是取消状态,所以每次都要创建一个新的CancellationTokenSource
            // 才行,也可以理解,如果这个TokenSource没有办法重启的话,就只能被取消一次,所以正确的做法就应该是在每个任务开启的时候创建一个TokenSource
            // 而不是在外面去创建
            GetImageTaskToken = new CancellationTokenSource();
            try
            {
                Task.Run(async () =>
                {
                    CanOpen = false;
                    while (!GetImageTaskToken.IsCancellationRequested)
                    {
                        await Task.Delay(5);
                        DataResult<int> checkXrayOnline = ImageCapture.Instance.CheckIsOnlineAndFlush();
                        if (checkXrayOnline.State)
                        {
                            // 如果两个都在线,就一直取图就可以了.
                            var result01 = ImageCapture.Instance.GetImage01();
                            if (result01.State)
                            {
                                ImageShowTool01 = result01.Data;
                            }
                            else
                            {
                                MessageProvider.ShowError(result01.Message!, "Xray01获取图像失败");
                            }

                            var result02 = ImageCapture.Instance.GetImage02();
                            if (result02.State)
                            {
                                ImageShowTool02 = result02.Data;
                            }
                            else
                            {
                                MessageProvider.ShowError(result02.Message!, "Xray02获取图像失败");
                            }

                        }
                        else
                        {
                            int dataRes = checkXrayOnline.Data;
                            if (dataRes == 1)
                            {
                                MessageProvider.ShowError("只有一个Xray在线,请检查另外一个Xray的USB线接口是否正确插入", "XrayUSB摄像头不在线");
                            }
                            else if (dataRes == 0)
                            {
                                MessageProvider.ShowError("两个Xray摄像头都不在线,请检查Xray的USB线接口是否正确插入", "两个XrayUSB摄像头都不在线");
                            }
                        }
                    }
                    // 循环退出的时候释放这个Token资源
                    GetImageTaskToken?.Dispose(); // 释放CancellationTokenSource资源
                    GetImageTaskToken = null; // 重置引用
                    ImageShowTool01 = null;
                    ImageShowTool02 = null;
                    ImageWidth = 0;
                    ImageHeight = 0;
                });
            }
            catch (Exception ex)
            {
                LogHelper.WriteLog(ex.GetFullException());
            }
        }

        /// <summary>
        /// 打开全部目录,并选择当前保存的文件
        /// </summary>
        public DelegateCommand OpenImageTotalCommand { get; private set; }

        /// <summary>
        /// 打开图像目录Xray02,并且选择当前保存的文件
        /// </summary>
        public DelegateCommand OpenImageXray02Command { get; private set; }

        /// <summary>
        /// 打开图像目录Xray01,并选择当前保存的文件
        /// </summary>
        public DelegateCommand OpenImageXray01Command { get; private set; }

        /// <summary>
        /// 保存Xray01图像
        /// </summary>
        public DelegateCommand KeepImageXray01Command { get; private set; }

        /// <summary>
        /// 保存Xray02图像
        /// </summary>
        public DelegateCommand KeepImageXray02Command { get; private set; }

        /// <summary>
        /// 同时保存两个Xray图像
        /// </summary>
        public DelegateCommand KeepImageTotalCommand { get; private set; }


        /// <summary>
        /// 打开实时显示图像的命令
        /// </summary>
        public DelegateCommand OpenGetImageCommand { get; private set; }
        /// <summary>
        /// 关闭实时显示图像的命令
        /// </summary>
        public DelegateCommand CloseGetImageCommand { get; private set; }


        private Mat? imageShowTool01;

        public Mat? ImageShowTool01
        {
            get { return imageShowTool01; }
            set
            {
                imageShowTool01 = value;
                RaisePropertyChanged();
            }
        }

        private Mat? imageShowTool02;

        public Mat? ImageShowTool02
        {
            get { return imageShowTool02; }
            set
            {
                imageShowTool02 = value;
                RaisePropertyChanged();
            }
        }



        /// <summary>
        /// 界面上显示的xray01的图像
        /// </summary>
        private Mat? imageResXray01;

        public Mat? ImageResXray01
        {
            get { return imageResXray01; }
            set
            {
                imageResXray01 = value;
                RaisePropertyChanged();
            }
        }

        /// <summary>
        /// 界面上显示的Xray02的图像
        /// </summary>
        private Mat? imageResXray02;

        public Mat? ImageResXray02
        {
            get { return imageResXray02; }
            set
            {
                imageResXray02 = value;
                RaisePropertyChanged();
            }
        }

        /// <summary>
        /// 前端界面显示的图像宽度
        /// </summary>
        private int imageWidth;

        public int ImageWidth
        {
            get { return imageWidth; }
            set { imageWidth = value; }
        }

        private int imageHeight;

        public int ImageHeight
        {
            get { return imageHeight; }
            set { imageHeight = value; }
        }



        private void TestXrayImageShow()
        {
            string imagePath01 = @"D:\template\Original\ok\1.bmp";
            string imagePath02 = @"D:\template\Original\ok\2.bmp";
            if (File.Exists(imagePath01))
            {
                ImageResXray01 = Cv2.ImRead(imagePath01, ImreadModes.Color);
            }
            if (File.Exists(imagePath02))
            {
                ImageResXray02 = Cv2.ImRead(imagePath02, ImreadModes.Color);
            }
        }

        private string? valtage01;

        public string? Valtage01
        {
            get { return valtage01; }
            set
            {
                valtage01 = value;
                RaisePropertyChanged();
            }
        }

        private string? valtage02;

        public string? Valtage02
        {
            get { return valtage02; }
            set
            {
                valtage02 = value;
                RaisePropertyChanged();
            }
        }


        private string? electricity01;

        public string? Electricity01
        {
            get { return electricity01; }
            set
            {
                electricity01 = value;
                RaisePropertyChanged();
            }
        }


        private string? electricity02;

        public string? Electricity02
        {
            get { return electricity02; }
            set
            {
                electricity02 = value;
                RaisePropertyChanged();
            }
        }


        /// <summary>
        /// 左Xray状态
        /// </summary>
        private DeviceState xrayLeftState = new DeviceState();

        public DeviceState XrayLeftState
        {
            get { return xrayLeftState; }
            set
            {
                xrayLeftState = value;
                RaisePropertyChanged();
            }
        }

        private DeviceState xrayRightState = new DeviceState();

        public DeviceState XrayRightState
        {
            get { return xrayRightState; }
            set
            {
                xrayRightState = value;
                RaisePropertyChanged();
            }
        }

        /// <summary>
        /// PLC运行状态
        /// </summary>
        private bool plcRunningState;

        public bool PlcRunningState
        {
            get { return plcRunningState; }
            set
            {
                plcRunningState = value;
                if (value)
                {
                    IsCheckedColor = new SolidColorBrush(Colors.Green);
                }
                RaisePropertyChanged();
            }
        }

        /// <summary>
        /// PLC停止状态
        /// </summary>
        private bool plcStopState;

        public bool PlcStopState
        {
            get { return plcStopState; }
            set
            {
                plcStopState = value;
                if (value)
                {
                    IsCheckedColor = new SolidColorBrush(Colors.Red);
                }
                RaisePropertyChanged();
            }
        }

        /// <summary>
        /// Plc复位状态
        /// </summary>
        private bool plcRestState;

        public bool PlcResetState
        {
            get { return plcRestState; }
            set { plcRestState = value; }
        }


        private SolidColorBrush? _isCheckedColor;

        public SolidColorBrush? IsCheckedColor
        {
            get { return _isCheckedColor; }
            set
            {
                _isCheckedColor = value;
                RaisePropertyChanged();
            }
        }



        /// <summary>
        /// 主PLC状态
        /// </summary>
        private DeviceState mainPlcState = new DeviceState();

        public DeviceState MainPlcState
        {
            get { return mainPlcState; }
            set
            {
                mainPlcState = value;
                RaisePropertyChanged();
            }
        }

        private void InitDeviceState()
        {
            XrayLeftState.DeviceName = "左相机";
            XrayLeftState.IsOnline = false;

            XrayRightState.DeviceName = "右相机";
            XrayRightState.IsOnline = false;

            MainPlcState.DeviceName = "PLC";
            MainPlcState.DeviceIp = "127.0.0.1";
            mainPlcState.DevicePort = 50000;
            mainPlcState.IsOnline = false;
        }

        private void InitWorkingInfo()
        {
            var result = WorkingInfoAccess.GetWorkingInfos();
            if (result.State)
            {
                if (result.Data!.Count == 0)
                {
                    // 如果无数据,就创建一条默认数据放进去
                    WorkingInfoEntity workinfo = new WorkingInfoEntity()
                    {
                        WorkingRecipeId = 1,
                        WorkingRecipeName = "Test001",
                        TemplateWidth = 30,
                        TemplateHeight = 100,
                        BorderIndex = 1,
                        BorderIndexMax = 1000,
                        CreateTime = DateTimeHelper.GetTimeNowForSql(),
                        UpdateTime = DateTimeHelper.GetTimeNowForSql(),
                    };
                    var addRes = WorkingInfoAccess.AddWorkingInfo(workinfo);
                    if (!addRes.State)
                    {
                        MessageProvider.ShowException(new Exception("数据库操作异常"), result.Message!);
                    }
                }
            }
            else
            {
                LogHelper.WriteLog("数据库操作异常" + result.Message!);
            }
        }

        public void RefreshWorkingInfo()
        {
            var result = WorkingInfoAccess.GetWorkingInfos();
            if (result.State)
            {
                WorkingInfos = new ObservableCollection<WorkingInfoEntity>(result.Data!);
                var workingId = WorkingInfos[0].WorkingRecipeId;
                var workingRecipe = WorkingInfos[0].WorkingRecipeName;
                // 根据这Id去查询其对应的工单是否存在,如果不存在就用工单里的最后的那个工单作为默认的工单
                var orderRes = OrderAccess.GetOrderById(workingId);
                if (orderRes.State)
                {
                    // 工单找到了,显示这个工单即可.
                    if (orderRes.Data != null)
                    {
                        WorkingOrders.Clear();
                        WorkingOrders.Add(orderRes.Data);
                        updateGlobalValues();
                    }
                    else
                    {
                        // 如果没有找到,就用工单中的默认的工单去做.
                        var ordersResult = OrderAccess.GetOrders();
                        if (ordersResult.State)
                        {
                            if (ordersResult.Data!.Count > 0)
                            {
                                // 取出最后一次创建的那个作业的工单,将这个工单作为新的工单
                                var orderUsed = ordersResult.Data.OrderByDescending(order => order.Id).ToList()[0];
                                WorkingOrders.Clear();
                                WorkingOrders.Add(orderUsed);
                                updateGlobalValues();

                                var workingInfo = WorkingInfos.FirstOrDefault();
                                if (workingInfo != null)
                                {
                                    workingInfo.WorkingRecipeId = orderUsed.Id;
                                    workingInfo.UpdateTime = DateTimeHelper.GetTimeNowForSql();
                                    workingInfo.WorkingRecipeName = orderUsed.RecipeName;

                                    var updateRes = WorkingInfoAccess.UpdateWorkingInfo(workingInfo);
                                    if (!updateRes.State)
                                    {
                                        MessageProvider.ShowException(new Exception("数据库操作异常"), updateRes.Message!);
                                    }
                                }
                            }
                        }
                        else
                        {
                            MessageProvider.ShowException(new Exception("数据库操作异常"), ordersResult.Message!);
                        }
                    }
                }
                else
                {
                    MessageProvider.ShowException(new Exception("数据库操作异常"), orderRes.Message!);
                }
            }
        }

        private ObservableCollection<WorkingInfoEntity> workingInfos = new ObservableCollection<WorkingInfoEntity>();
        public ObservableCollection<WorkingInfoEntity> WorkingInfos
        {
            get { return workingInfos; }
            set
            {
                workingInfos = value;
                RaisePropertyChanged();
            }
        }


        private ObservableCollection<OrderEntity> workingOrders = new ObservableCollection<OrderEntity>();
        public ObservableCollection<OrderEntity> WorkingOrders
        {
            get { return workingOrders; }
            set
            {
                workingOrders = value;

                updateGlobalValues();

                RaisePropertyChanged();
            }
        }

        private void updateGlobalValues()
        {
            if (WorkingOrders.Count > 0)
            {
                var workOrder = WorkingOrders[0];
                // 在这里更新当前作业的批号
                GlobalValues.currentLotId = workOrder.LotId;
                GlobalValues.currentOrderId = workOrder.RecipeName!;
                GlobalValues.disX = workOrder.LongLengthX;
                GlobalValues.disY = workOrder.ShortLengthY;
                GlobalValues.disF = workOrder.DirectHoleDisF;
                GlobalValues.disD = workOrder.FrontEdgeDisD;
                GlobalValues.firstOffset = workOrder.MoveOffset;
                GlobalValues.secondOffset = workOrder.MoveOffset02;
                GlobalValues.okCount = workOrder.OkCount;
                GlobalValues.ngCount = workOrder.FailCount;
                GlobalValues.totalCount = workOrder.Count;
            }
        }

        private void RefreshWorkingOrder()
        {
            // 1. 先从WorkingInfo里面获取当前作业的工单Id
        }

        private void InitOrder()
        {
            var orderResult = OrderAccess.GetOrders();
            if (orderResult.State)
            {
                if (orderResult.Data!.Count == 0)
                {
                    // 只有当数据不存在的时候才会去创建一个模拟数据
                    OrderEntity order = new OrderEntity()
                    {
                        RecipeName = "Test001",
                        CreateTime = DateTimeHelper.GetTimeNowForSql(),
                        LongLengthX = 400.12,
                        ShortLengthY = 300.34,
                        FrontEdgeDisD = 200,
                        DirectHoleDisF = 50,
                        FailCount = 3,
                        OkCount = 2,
                        Count = 5,
                        UpdateTime = DateTimeHelper.GetTimeNowForSql(),
                    };
                    var addRes = OrderAccess.AddOrder(order);
                    if (!addRes.State)
                    {
                        MessageProvider.ShowException(new Exception("数据库操作异常"), orderResult.Message!);
                    }
                }
            }
            else
            {
                MessageProvider.ShowException(new Exception("数据库操作异常"), orderResult.Message!);
            }

        }

    }
}
